#include "mmap_file_op.h"
#include "common.h"

static int debug = 1;

namespace project
{
    namespace largefile
    {
        int MMapFileOperation::mmap_file(const MMapOption &mmap_option)
        {
            // 对传入的mmap_option进行合法性的检查
            // 如果最大映射大小小于第一次可以映射的大小或者最大映射大小小于等于0，则报错
            if (mmap_option.max_mmap_size_ < mmap_option.first_mmap_size_)
            {
                return TFS_ERROR;
            }
            if (mmap_option.max_mmap_size_ <= 0)
            {
                return TFS_ERROR;
            }

            // 检查文件是否打开
            int fd = check_file();
            if (fd < 0)
            {
                fprintf(stderr, "MMapFileOperation::mmap_file checking file failed!");
                return TFS_ERROR;
            }

            // 如果未进行映射，则进行映射
            if (!is_mapped_)
            {
                if (map_file_)
                    delete (map_file_);

                map_file_ = new MMapFile(mmap_option, fd);
                is_mapped_ = map_file_->map_file(true);
            }
            // 判断是否映射成功
            if (is_mapped_)
            {
                return TFS_SUCCESS;
            }
            else
            {
                return TFS_ERROR;
            }
        }

        int MMapFileOperation::munmap_file()
        {
            // 如果已经映射成功了，则解除映射
            if (is_mapped_ && map_file_ != NULL)
            {
                delete (map_file_);
                is_mapped_ = false;
            }

            return TFS_SUCCESS;
        }

        void *MMapFileOperation::get_map_data() const
        {
            if (is_mapped_)
            {
                return map_file_->get_data();
            }

            return NULL;
        }

        // 如果内存映射了，则从内存中读取文件，如果内存没有映射或者映射补全，则在磁盘中读取文件
        int MMapFileOperation::pread_file(char *buf, const int32_t size, const int64_t offset)
        {
            //1、内存已经映射
            // 内存映射的大小不够,扩容(增加映射的内存)
            if(is_mapped_ && (offset + size) > map_file_->get_size()) {
                if(debug) fprintf(stdout, "MMapFileOperation::pread, size:%d, offset:%" __PRI64_PREFIX "d,map file size:%d, need remap\n",
                    size, offset, map_file_->get_size());

                map_file_->remap_file();
            }

            // 从内存中直接copy一份到buffer中
            if(is_mapped_ && (offset + size) <= map_file_->get_size()) {
                memcpy(buf, (char*)map_file_->get_data() + offset, size);
                return TFS_SUCCESS;
            }

            
            //2、内存没有映射或映射不全
            return FileOperation::pread_file(buf, size, offset);

        }

        int MMapFileOperation::pwrite_file(const char *buf, const int32_t size, const int64_t offset) {
            //1、内存已经映射
            if(is_mapped_ && (offset + size) > map_file_->get_size()) {
                if(debug) fprintf(stdout, "MMapFileOperation::write, size:%d, offset:%" __PRI64_PREFIX "d,map file size:%d, need remap\n",
                    size, offset, map_file_->get_size());

                map_file_->remap_file();
            }

            // 从内存中直接copy一份到buffer中
            if(is_mapped_ && (offset + size) <= map_file_->get_size()) {
                memcpy((char*)map_file_->get_data() + offset, buf, size);
                return TFS_SUCCESS;
            }

            
            //2、内存没有映射或映射不全
            return FileOperation::pwrite_file(buf, size, offset);
        }


        int MMapFileOperation::flush_file() {
            if(is_mapped_) {
                if(map_file_->sync_file()) return TFS_SUCCESS;
                else return TFS_ERROR;
            }

            return FileOperation::flush_file();
        }

    }
}